package com.lotso.web.common.config;

import com.lotso.web.module.batch.listener.CustomGlobalJobListener;
import org.quartz.Scheduler;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.Properties;

/**
 * ClassName: QuartzSchedulerConfig
 * Description: QuartzScheduler 配置
 * Date: 2018/9/6 16:45 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 * @Deprecated 使用 Springboot starter 替换，配置文件可见 {@link QuartzAutoConfiguration}。
 * 在此基础上如需自定义 {@link SchedulerFactoryBeanCustomizerConfig}
 */
@Deprecated
@Configuration
@ConditionalOnProperty(prefix = "lotso.web.quartz", name = "enabled", havingValue = "true")
public class QuartzSchedulerConfig {

    /**
     * 配置自定义 JobFactory
     *
     * @param applicationContext
     * @return
     */
    @Bean
    public JobFactory jobFactory(ApplicationContext applicationContext) {
        return new AutowireCapableBeanJobFactory(applicationContext.getAutowireCapableBeanFactory());
    }


    @Bean
    public CustomGlobalJobListener globalJobListener() {
        return new CustomGlobalJobListener();
    }

    /**
     * 配置调度工厂
     *
     * @return
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws Exception {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // this allows to update triggers in DB when updating settings in config file
        factory.setOverwriteExistingJobs(true);
        // use specify jobFactory to create jobDetail
        factory.setJobFactory(jobFactory);
        // 全局监听器
        factory.setGlobalJobListeners(globalJobListener());
        // 参数配置
        factory.setQuartzProperties(quartzProperties());
        // 延迟启动
        factory.setStartupDelay(5);
        return factory;
    }

    @Bean
    public Scheduler scheduler(JobFactory jobFactory, SchedulerFactoryBean schedulerFactoryBean) throws Exception {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        scheduler.setJobFactory(jobFactory);
        return scheduler;
    }

    /**
     * Quartz 配置文件
     *
     * @return
     * @throws IOException
     */
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    /**
     * ClassName: AutowireCapableBeanJobFactory
     * Description: Quartz Job 中支持 autowiring
     * Date: 2018/9/6 16:45 【需求编号】
     *
     * @author Sam Sho
     * @version V1.0.0
     * @see org.springframework.boot.autoconfigure.quartz.AutowireCapableBeanJobFactory
     */
    static class AutowireCapableBeanJobFactory extends SpringBeanJobFactory {

        private final AutowireCapableBeanFactory beanFactory;

        AutowireCapableBeanJobFactory(AutowireCapableBeanFactory beanFactory) {
            Assert.notNull(beanFactory, "Bean factory must not be null");
            this.beanFactory = beanFactory;
        }

        @Override
        protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
            Object jobInstance = super.createJobInstance(bundle);
            this.beanFactory.autowireBean(jobInstance);
            this.beanFactory.initializeBean(jobInstance, null);
            return jobInstance;
        }

    }
}
